package com.example.ddz.framework;

/**
 * Created by IntelliJ IDEA.
 * User: Marcel Melzig
 * Date: 09.08.11
 * Time: 20:07
 */

import java.io.IOException;
import java.io.InputStream;

import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;

public class AndroidGraphics implements IGraphics
{
    private final AssetManager assets;
    private final Bitmap frameBuffer;
    private final Canvas canvas;
    private final Paint paint;
    private final Rect srcRect = new Rect();
    private final Rect dstRect = new Rect();
    private final float scaleX;
    private final float scaleY;

    /**
     * Creates an instance of the AndroidGraphics class.
     *
     * @param assets      The asset manager manages all graphics stored in the asset storage.
     * @param frameBuffer The framebuffer the graphics will be printed to.
     * @param scaleX      A factor used to resize the loaded graphics.
     * @param scaleY      A factor used to resize the loaded graphics.
     */
    public AndroidGraphics(AssetManager assets, Bitmap frameBuffer, float scaleX, float scaleY)
    {
        this.assets = assets;
        this.frameBuffer = frameBuffer;
        this.canvas = new Canvas(frameBuffer);
        this.paint = new Paint();
        this.scaleX = scaleX;
        this.scaleY = scaleY;
    }

    /**
     * Creates a pixmap object.
     *
     * @param fileName the filename.
     * @param format   The format of the given file.
     * @return A pixmap object.
     */
    @Override
    public IPixmap NewPixmap(String fileName, PixmapFormat format)
    {
        Config config;

        if (format == PixmapFormat.RGB565)
            config = Config.RGB_565;
        else if (format == PixmapFormat.ARGB4444)
            config = Config.ARGB_4444;
        else
            config = Config.ARGB_8888;

        Options options = new Options();
        options.inPreferredConfig = config;
        InputStream in = null;
        Bitmap bitmap = null;
        try
        {
            in = assets.open(fileName);
            bitmap = BitmapFactory.decodeStream(in);

            if (bitmap == null)
                throw new RuntimeException("Couldn't load bitmap from asset '" + fileName + "'");
        }
        catch (IOException e)
        {
            throw new RuntimeException("Couldn't load bitmap from asset '" + fileName + "'");
        }
        finally
        {
            if (in != null)
            {
                try
                {
                    in.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }

        bitmap = this.ScaleBitmap(bitmap);

        if (bitmap.getConfig() == Config.RGB_565)
            format = PixmapFormat.RGB565;
        else if (bitmap.getConfig() == Config.ARGB_4444)
            format = PixmapFormat.ARGB4444;
        else
            format = PixmapFormat.ARGB8888;

        return new AndroidPixmap(bitmap, format);
    }

    /**
     * Scales a bitmap to the screens dimensions. The method is used to scale all bitmaps in the assets folder while
     * loading. The Assets-class stores the scaled instances of the bitmaps to use them in the game. The scale factor
     * passed to this class is used to scale the images to the right dimensions.
     *
     * @param bitmap The bitmap that should be scaled.
     * @return The scaled bitmap.
     */
    private Bitmap ScaleBitmap(Bitmap bitmap)
    {
        if (bitmap == null)
            return null;

        int width = (int) (bitmap.getWidth() * scaleX);
        int height = (int) (bitmap.getHeight() * scaleY);

        return Bitmap.createScaledBitmap(bitmap, width, height, true);
    }

    /**
     * Clears the canvas by removing all color information.
     *
     * @param color The color which should be cleared.
     */
    @Override
    public void Clear(int color)
    {
        canvas.drawRGB((color & 0xff0000) >> 16, (color & 0xff00) >> 8, (color & 0xff));
    }

    /**
     * Draws a pixel to the framebuffer.
     *
     * @param x     The x coordinate of the pixel.
     * @param y     The y coordinate of the pixel.
     * @param color The color the pixel is been set to.
     */
    @Override
    public void DrawPixel(int x, int y, int color)
    {
        paint.setColor(color);
        canvas.drawPoint(x, y, paint);
    }

    /**
     * Draws a line to the framebuffer.
     *
     * @param x     The x coordinate of the line.
     * @param y     The y coordinate of the line.
     * @param x2    The destination x coordinate of the line.
     * @param y2    The destination y coordinate of the line.
     * @param color The color of the line.
     */
    @Override
    public void DrawLine(int x, int y, int x2, int y2, int color)
    {
        paint.setColor(color);
        canvas.drawLine(x, y, x2, y2, paint);
    }

    /**
     * Draws a rectangle to the framebuffer.
     *
     * @param x      The x coordinate the rectangle drawing starts from.
     * @param y      The y coordinate the rectangle drawing starts from.
     * @param width  The width of the rectangle.
     * @param height The height of the rectangle.
     * @param color  The color of the rectangle.
     */
    @Override
    public void DrawRec(int x, int y, int height, int width, int color)
    {
        paint.setColor(color);
        paint.setStyle(Style.FILL);
        canvas.drawRect(x, y, x + width - 1, y + height - 1, paint);
    }

    /**
     * Draws part of a pixmap to the framebuffer.
     *
     * @param pixmap    The pixmap.
     * @param x         The x coordinate.
     * @param y         The y coordinate.
     * @param srcX      The x coordinate of the source pixmap.
     * @param srcY      The y coordinate of the source pixmap.
     * @param srcWidth  The width of the source pixmap.
     * @param srcHeight The height of the source pixmap.
     */
    @Override
    public void DrawPixmap(IPixmap pixmap, int x, int y, int srcX, int srcY, int srcWidth, int srcHeight)
    {
        srcRect.left = srcX;
        srcRect.top = srcY;
        srcRect.right = srcX + srcWidth - 1;
        srcRect.bottom = srcY + srcHeight - 1;
        dstRect.left = x;
        dstRect.top = y;
        dstRect.right = x + srcWidth - 1;
        dstRect.bottom = y + srcHeight - 1;
        canvas.drawBitmap(((AndroidPixmap) pixmap).bitmap, srcRect, dstRect, null);
    }

    /**
     * Draws a pixmap to the framebuffer.
     *
     * @param pixmap The pixmap.
     * @param x      The x coordinate.
     * @param y      The y coordinate.
     */
    @Override
    public void DrawPixmap(IPixmap pixmap, int x, int y)
    {
        canvas.drawBitmap(((AndroidPixmap) pixmap).bitmap, x, y, null);
    }

    /**
     * Gets the width of the framebuffer.
     *
     * @return The width of the framebuffer.
     */
    @Override
    public int GetWidth()
    {
        return frameBuffer.getWidth();
    }

    /**
     * Gets the height of the framebuffer.
     *
     * @return The height of the framebuffer.
     */
    @Override
    public int GetHeight()
    {
        return frameBuffer.getHeight();
    }
}
